<body></body>
<script>
  let activeEffect = null
  const effectStack = [] //effect栈
  const bucket = new WeakMap()
  const data = {
    foo: true,
    bar: true
  }

  const obj = new Proxy(data, {
    get(target, key) {
      track(target, key)
      return target[key]
    },
    set(target, key, newVal) {
      target[key] = newVal
      trigger(target, key)
    }
  })

  function track(target, key) {
    if (!activeEffect) return
    let depMap = bucket.get(target)
    if (!depMap) {
      bucket.set(target, (depMap = new Map()))
    }

    let deps = depMap.get(key)
    if (!deps) {
      depMap.set(key, (deps = new Set()))
    }
    const effectSet = deps.add(activeEffect)
    activeEffect.deps.push(effectSet)
  }

  function trigger(target, key) {
    let depMap = bucket.get(target)
    if (!depMap) return
    const depsSet = depMap.get(key)
    const effectsToRun = new Set(depsSet)
    effectsToRun && effectsToRun.forEach(effectFn => effectFn())
  }

  function effect(fn) {
    function effectFn() {
      cleanup(effectFn)
      //当调用 effect 注册副作用函数时，将副作用函数复制给 activeEffect
      activeEffect = effectFn //注册 effectFn 内存指针, 用于 deps.add(activeEffect)

      // 在调用副作用函数之前将当前副作用压入栈中
      effectStack.push(effectFn)
      fn()
      // 在当前副作用执行完毕后，将当前副作用函数弹出栈，并把 activeEffect 还原为之前的值
      effectStack.pop(effectFn)
      activeEffect = effectStack[effectStack.length - 1]
    }
    effectFn.deps = [] //反向收集 effectSet的引用
    effectFn()
  }
  function cleanup(effectFn) {
    effectFn.deps.forEach(depSet => {
      depSet.delete(effectFn)
    })
    effectFn.deps.length = 0
  }

  let temp1, temp2
  effect(function effectFn1() {
    console.log('effectFn1执行')

    effect(function effectFn() {
      console.log('effectFn2执行')
      temp2 = obj.bar
    })
    temp1 = obj.foo
  })
  obj.foo = 123 //effectFn1包含effectFn2的执行
</script>
